/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Processing;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 *
 */

public class ChessBoard extends Board
{
    private static byte[] InitPawnList = { ChessPawn.XeDen, ChessPawn.MaDen, ChessPawn.TuongDen, ChessPawn.HauDen, ChessPawn.VuaDen, ChessPawn.TuongDen, ChessPawn.MaDen, ChessPawn.XeDen };
    private static int[][] PawnMoveList = { { 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
                                            { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 },
                                            { 4, 1, 0, -1, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 30 },
                                            { 8, 0, 0, -2, -1, -2, 1, -1, -2, -1, 2, 1, -2, 1, 2, 2, -1, 2, 1, 13 },
                                            { 4, 1, 0, -1, -1, -1, 1, 1, -1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 10 },
                                            { 8, 1, 0, -1, -1, -1, 1, 1, -1, 1, 1, -1, 0, 1, 0, 0, -1, 0, 1, 50 },
                                            { 8, 0, 0, -1, -1, -1, 1, 1, -1, 1, 1, -1, 0, 1, 0, 0, -1, 0, 1, 10000 },
                                            { 1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 },
                                            { 4, 1, 1, -1, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 30 },
                                            { 8, 0, 1, -2, -1, -2, 1, -1, -2, -1, 2, 1, -2, 1, 2, 2, -1, 2, 1, 13 },
                                            { 4, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 10 },
                                            { 8, 1, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 0, 1, 0, 0, -1, 0, 1, 50 },
                                            { 8, 0, 1, -1, -1, -1, 1, 1, -1, 1, 1, -1, 0, 1, 0, 0, -1, 0, 1, 10000 } };
    private static int EstimatedCost = 19;


    public void InitBoard(int firstPawn)
    {
        wonPawnList = new Vector[2];
        wonPawnList[0] = new Vector();
        wonPawnList[1] = new Vector();
        currentPawnList = new Hashtable[2];
        currentPawnList[0] = new Hashtable();
        currentPawnList[1] = new Hashtable();
        m_Board = new byte[64];
        for (int i = 0; i < 8; i++)
        {
            PlaceAPawn(0, i, InitPawnList[i]);
            currentPawnList[0].put(new Integer(i), new Integer(InitPawnList[i]));
            PlaceAPawn(7, i, (InitPawnList[i] + 6));
            currentPawnList[1].put(new Integer(i + 56), new Integer(InitPawnList[i] + 6));
            PlaceAPawn(1, i, ChessPawn.TotDen);
            currentPawnList[0].put(new Integer(i + 8), new Integer(ChessPawn.TotDen));
            PlaceAPawn(6, i, ChessPawn.TotTrang);
            currentPawnList[1].put(new Integer(i + 48), new Integer(ChessPawn.TotTrang));
        }
        m_MoveList = new Vector();
        MovablePawn = firstPawn;
    }

    public void LoadBoard(byte[] dl)
    {
        wonPawnList = new Vector[2];
        wonPawnList[0] = new Vector();
        wonPawnList[1] = new Vector();
        currentPawnList = new Hashtable[2];
        currentPawnList[0] = new Hashtable();
        currentPawnList[1] = new Hashtable();
        m_Board = new byte[64];

        int cs = 0;
        for (int i = 0; i < 2; ++i)
        {
            while (dl[++cs] != -1)
            {
                currentPawnList[i].put(new Integer(dl[cs]), new Integer(dl[cs + 1]));
                m_Board[(int)dl[cs]] = (byte)dl[cs + 1];
                ++cs;
            }

            while (dl[++cs] != -1)
            {
                wonPawnList[i].addElement(new Integer(dl[cs]));
            }
        }

        m_MoveList = new Vector();
        MovablePawn = dl[0];
    }

    protected boolean PlaceAPawn(int x, int y, int chessType)
    {
        if (x >= 0 && x < 8 && y >= 0 && y < 8)
        {
            m_Board[8 * x + y] = (byte)chessType;
            return true;
        }
        return false;
    }

    protected boolean PlaceAPawn(int pos, int pawn)
    {
        if (pos < 0 || pos >= 64)
            return false;
        int vtHang = pos / 8;
        int vtCot = pos % 8;
        return PlaceAPawn(vtHang, vtCot, pawn);
    }

    public boolean WinningCheck(int chessType)
    {
        boolean kq = false;

        if (chessType == 0)
        {
            if (!currentPawnList[0].contains(new Integer(ChessPawn.VuaDen)))
                kq = true;
        }
        else
        {
            if (!currentPawnList[1].contains(new Integer(ChessPawn.VuaTrang)))
                kq = true;
        }

        return kq;
    }

    public boolean Win()
    {
        if(WinningCheck(0) || WinningCheck(1))
            return true;
        return false;
    }

    public int isPawn(int qc)
    {
        return PawnMoveList[qc][2];
    }

    public int isKing(int qc)
    {
        int result = -1;
        if (PawnMoveList[qc][EstimatedCost] == 10000)
        {
            result = PawnMoveList[qc][2];
        }
        return result;
    }

    public Vector MovableTurnList(int x, int y)
    {
        byte currentPawn = GetSquare(x, y);
        byte nextPawn = ChessPawn.OTrong;
        if (currentPawn == ChessPawn.OTrong)
            return null;
        Vector result = new Vector();
        int takablePawn = 0;
        int protectedPawn = 0;
        int temp;
        for (int i = 0; i < PawnMoveList[(int)currentPawn][0]; i++)
        {
            int nextX = x;
            int nextY = y;
            if (PawnMoveList[(int)currentPawn][1] == 0)
            {
                nextX += PawnMoveList[(int)currentPawn][2 * i + 3];
                nextY += PawnMoveList[(int)currentPawn][2 * i + 4];
                if (nextX < 0 || nextX > 7 || nextY < 0 || nextY > 7)
                    continue;
                int nextMove = 8 * nextX + nextY;
                nextPawn = GetSquare(nextMove);

                //xét ăn chéo của tốt
                if (currentPawn == ChessPawn.TotDen || currentPawn == ChessPawn.TotTrang)
                {
                    if (nextY > 0)
                        if (PawnMoveList[(int)GetSquare(nextX, nextY - 1)][2] != -1)
                        {
                            temp = 8 * nextX + (nextY - 1);
                            if (PawnMoveList[(int)GetSquare(nextX, nextY - 1)][2] != PawnMoveList[(int)currentPawn][2])
                            {
                                takablePawn += PawnMoveList[(int)m_Board[temp]][EstimatedCost];
                                result.addElement(new Integer(temp));
                            }
                            else
                            {
                                protectedPawn += PawnMoveList[(int)m_Board[temp]][EstimatedCost];
                            }
                        }
                    if (nextY < 7)
                        if (PawnMoveList[(int)GetSquare(nextX, nextY + 1)][2] != -1)
                        {
                            temp = 8 * nextX + (nextY + 1);
                            if (PawnMoveList[(int)GetSquare(nextX, nextY + 1)][2] != PawnMoveList[(int)currentPawn][2])
                            {
                                takablePawn += PawnMoveList[(int)m_Board[temp]][EstimatedCost];
                                result.addElement(new Integer(temp));
                            }
                            else
                            {
                                protectedPawn += PawnMoveList[(int)m_Board[temp]][EstimatedCost];
                            }
                        }
                }
                //xét cùng phe
                if (PawnMoveList[(int)nextPawn][2] == PawnMoveList[(int)currentPawn][2])
                {
                    protectedPawn += PawnMoveList[(int)nextPawn][EstimatedCost];
                    continue;
                }
                else if (PawnMoveList[(int)nextPawn][2] != -1)
                {
                    //là tốt thì bỏ qua
                    if (currentPawn == ChessPawn.TotDen || currentPawn == ChessPawn.TotTrang)
                        continue;

                    takablePawn += PawnMoveList[(int)nextPawn][EstimatedCost];
                }
                result.addElement(new Integer(nextMove));

                //xét tốt đi khởi đầu
                byte tempXT = ChessPawn.OTrong;
                if (currentPawn == ChessPawn.TotDen && x == 1)
                {
                    nextPawn = GetSquare(3, y);
                    tempXT = GetSquare(2, y);
                    if (nextPawn == ChessPawn.OTrong && tempXT == ChessPawn.OTrong)
                        result.addElement(new Integer(8 * 3 + y));
                }
                if (currentPawn == ChessPawn.TotTrang && x == 6)
                {
                    nextPawn = GetSquare(4, y);
                    tempXT = GetSquare(5, y);
                    if (nextPawn == ChessPawn.OTrong && tempXT == ChessPawn.OTrong)
                        result.addElement(new Integer(8 * 4 + y));
                }
            }
            else
            {
                while (true)
                {
                    nextX += PawnMoveList[(int)currentPawn][2 * i + 3];
                    nextY += PawnMoveList[(int)currentPawn][2 * i + 4];
                    if (nextX < 0 || nextX > 7 || nextY < 0 || nextY > 7)
                        break;
                    int nuocdiTiepTheo = 8 * nextX + nextY;
                    nextPawn = GetSquare(nuocdiTiepTheo);
                    if (PawnMoveList[(int)nextPawn][2] == PawnMoveList[(int)currentPawn][2])
                    {
                        protectedPawn += PawnMoveList[(int)nextPawn][EstimatedCost];
                        break;
                    }
                    else if (PawnMoveList[(int)nextPawn][2] != -1)
                    {
                        result.addElement(new Integer(nuocdiTiepTheo));
                        takablePawn += PawnMoveList[(int)nextPawn][EstimatedCost];
                        break;
                    }
                    result.addElement(new Integer(nuocdiTiepTheo));
                }
            }
        }
        result.addElement(new Integer(protectedPawn));
        result.addElement(new Integer(takablePawn));
        return result;
    }

    public Vector MovableList(int pos)
    {
        int x = pos / 8;
        int y = pos % 8;
        return MovableTurnList(x, y);
    }

    public int[] PlaceAMove(int startPos, int destPos, int pawnPromotionType)
    {
        if (startPos >= 0 && destPos >= 0 && startPos < 64 && destPos < 64)
        {
            byte currentPawn = GetSquare(startPos);
            byte destPawn = GetSquare(destPos);
            if (PawnMoveList[(int)currentPawn][2] != MovablePawn || !currentPawnList[MovablePawn].containsKey(new Integer(startPos)))
                return null;
            Vector movableTurnList = MovableList(startPos);
            if (movableTurnList.indexOf(new Integer(destPos)) == -1)
                return null;
            PlaceAPawn(startPos, (int)ChessPawn.OTrong);
            PlaceAPawn(destPos, (int)currentPawn);

            int movablePawnList = (MovablePawn == 0) ? 1 : 0;
            currentPawnList[MovablePawn].remove(new Integer(startPos));
            currentPawnList[MovablePawn].put(new Integer(destPos), new Integer(currentPawn));
            if (currentPawnList[movablePawnList].containsKey(new Integer(destPos)))
            {
                wonPawnList[MovablePawn].addElement(currentPawnList[movablePawnList].get(new Integer(destPos)));
                currentPawnList[movablePawnList].remove(new Integer(destPos));
            }
            MovablePawn = movablePawnList;
            int[] result = new int[2];
            result[0] = -1;
            if (pawnPromotionType != 0)
            {
                result = PawnPromotion(destPos, pawnPromotionType);
            }

            String temp = "";
            temp += String.valueOf(startPos) + "_" + String.valueOf((int)currentPawn) + "_";
            if (result[0] != -1)
                temp += String.valueOf(result[1]) + ";";
            else
                temp += String.valueOf((int)currentPawn) + ";";
            temp += String.valueOf(destPos) + "_" + String.valueOf((int)destPawn);
            m_MoveList.addElement(temp);
            if (m_MoveList.size() > 20)
                m_MoveList.removeElementAt(0);

            return result;
        }
        return null;
    }

    public int[] PlaceAMove(int vitriDau, int vitriSau)
    {
        return PlaceAMove(vitriDau, vitriSau, 1);
    }

    public int[] CompMove()
    {
        int[] result = new int[2];

        boolean canCheckmate = false;
        int kingEstimated = 0;
        String strMove = "";
        String strCurMove = "";
        int estCost = Integer.MAX_VALUE;
        Enumeration en = currentPawnList[MovablePawn].keys();
        while(en.hasMoreElements())
        {
            int each = ((Integer)en.nextElement()).intValue();
            if (canCheckmate)
                break;
            if (GetSquare(each) == ChessPawn.VuaDen || GetSquare(each) == ChessPawn.VuaTrang)
                kingEstimated = 5;
            else
                kingEstimated = 0;
            Vector nextMoveList = MovableList(each);
            for (int i = 0; i < nextMoveList.size() - 2; i++)
            {
                int takablePawn = kingEstimated;
                int nextMove = ((Integer)nextMoveList.elementAt(i)).intValue();
                strMove = String.valueOf(each) + "_" + String.valueOf(nextMove);
                if (GetSquare(nextMove) == ChessPawn.VuaDen || GetSquare(nextMove) == ChessPawn.VuaTrang)
                {
                    canCheckmate = true;
                    strCurMove = strMove;
                    estCost = -20000;
                    break;
                }
                ChessBoard temp = new ChessBoard(this);
                int[] moveResult = temp.PlaceAMove(each, nextMove, 1);
                if (m_Board[nextMove] != 0)
                {
                    takablePawn -= PawnMoveList[(int)m_Board[nextMove]][EstimatedCost];
                }

                if (moveResult[0] != -1)
                    takablePawn -= 30;

                Vector tempNextMove = null;
                Enumeration enTemp = temp.currentPawnList[temp.MovablePawn].keys();
                while(enTemp.hasMoreElements())
                {
                    int curPawn = ((Integer)enTemp.nextElement()).intValue();
                    tempNextMove = temp.MovableList(curPawn);
                    takablePawn += ((Integer)tempNextMove.elementAt(tempNextMove.size() - 1)).intValue();
                }

                tempNextMove = temp.MovableList(nextMove);
                int tempTakablePawn = ((Integer)tempNextMove.elementAt(tempNextMove.size() - 1)).intValue();
                if (tempTakablePawn >= 10000)
                {
                    takablePawn -= 2;
                }
                //soQuanAnDuoc -= tempNuocDiKe[tempNuocDiKe.Count - 2]/10;
                if(estCost > takablePawn)
                {
                    estCost = takablePawn;
                    strCurMove = strMove;
                }
            }
        }

        String[] tempKQ = Util.Split(strCurMove, "_");
        result[0] = Integer.parseInt(tempKQ[0]);
        result[1] = Integer.parseInt(tempKQ[1]);

        return result;
    }


    public byte GetSquare(int x, int y)
    {
        if (x >= 0 && x < 8 && y >= 0 && y < 8)
        {
            return m_Board[8 * x + y];
        }
        return ChessPawn.OTrong;
    }

    public byte GetSquare(int pos)
    {
        if (pos >= 0 && pos < 64)
        {
            return m_Board[pos];
        }
        return ChessPawn.OTrong;
    }

    // hàm thực hiện chức năng phong tốt, với 1: hậu , 2: xe , 3: mã , 4: tượng
    private int[] PawnPromotion(int pos, int pawnType)
    {
        byte curPos = m_Board[pos];
        int cons = pos / 8;
        int[] result = new int[2];
        result[0] = -1;
        if (curPos != ChessPawn.TotDen && curPos != ChessPawn.TotTrang)
            return result;
        if (curPos == ChessPawn.TotDen && cons != 7)
            return result;
        if (curPos == ChessPawn.TotTrang && cons != 0)
            return result;

        result[0] = pos;
        switch (pawnType)
        {
            case 1:     // phong hậu
                m_Board[pos] += 4;
                result[1] = m_Board[pos];
                break;
            case 2:     // phong xe
                m_Board[pos] += 1;
                result[1] = m_Board[pos];
                break;
            case 3:     // phong mã
                m_Board[pos] += 2;
                result[1] = m_Board[pos];
                break;
            case 4:     // phong tượng
                m_Board[pos] += 3;
                result[1] = m_Board[pos];
                break;
        }
        currentPawnList[1 - (((int)curPos) % 7)].remove(new Integer(pos));
        currentPawnList[1 - (((int)curPos) % 7)].put(new Integer(pos), new Integer(m_Board[pos]));
        return result;
    }


    public ChessBoard()
    {
    }

    public ChessBoard(boolean isWhite)
    {
        if (isWhite)
            MovablePawn = 1;
        else
            MovablePawn = 0;
    }

    public ChessBoard(ChessBoard a)
    {
        m_Board = new byte[64];
        for(int i=0; i<m_Board.length; ++i)
        {
            m_Board[i] = a.m_Board[i];
        }
        m_MoveList = new Vector();
        for(int i=0; i<a.m_MoveList.size(); ++i)
        {
            m_MoveList.addElement(a.m_MoveList.elementAt(i));
        }
        MovablePawn = a.MovablePawn;
        currentPawnList = new Hashtable[2];
        wonPawnList = new Vector[2];
        for (int i = 0; i < 2; i++)
        {
            currentPawnList[i] = new Hashtable();
            Enumeration en = a.currentPawnList[i].keys();
            while(en.hasMoreElements())
            {
                Integer each = (Integer)en.nextElement();
                currentPawnList[i].put(each, a.currentPawnList[i].get(each));
            }
            wonPawnList[i] = new Vector();
            en = a.wonPawnList[i].elements();
            while(en.hasMoreElements())
            {
                wonPawnList[i].addElement(en.nextElement());
            }
        }
    }
}
